// Gramatyka drzewiasta - z niej zostanie zbudowany parser, ktory bedzie przeprowadzal konkretne obliczenia

tree grammar FOLStage4;

options
{
	tokenVocab=FOLStage2;
	ASTLabelType=CommonTree;
	output=AST;
}

@header
{
package org.protege.owl.examples.tab.grammar;

import org.protege.owl.examples.tab.*;
import java.util.Iterator;
import java.util.ArrayList;
}

@members
{
public void setEnvironment(PredicateRegistry pr, VariableRegistry vr)
{
	predicateRegistry = pr;
	variableRegistry = vr;
	variableRegistry.clear();
	return;
}

public void clear()
{
	quantifierResultList.clear();
	quantifierString = "";
	return;
}

public ResultTable getResultTable()
{
	return queryResultTable;
}

private void executeQuery()
{
	try
	{
		int size = quantifierString.length();
   	for (int i=size-1;i>=0;i--)
   	{
   		// Zlaczenie ze zliczaniem dopasowania dla pierszej tabeli
   		Integer fitSize = 0;
   		queryResultTable = ResultTable.and(quantifierResultList.get(i), queryResultTable, fitSize);
   		fitSize = ResultTable.getFitSize();
   		   		
   		System.out.println("Fit size:" + fitSize);
   		// Sprawdzenie spelnialnosci kwantyfikatora
   		int resultSize = queryResultTable.size();
   		int quantifierSize = quantifierResultList.get(i).size();
   		String quantifierKind = quantifierString.substring(i,i+1);
   		// Kwantyfikator ogolny
   		if (quantifierKind.compareTo("A")==0)
   		{
   			// a moze odwrotnie -> quantifierSize < resultSize ?
   			if (fitSize<quantifierSize)
   			{
   				queryResultTable = new ResultTable();
   				break;
   			}
   		}
   		else
   		// Kwantyfikator szczegolny
   		if (quantifierKind.compareTo("E")==0)
   		{
   			if (fitSize<1)
   			{
   				queryResultTable = new ResultTable();
   				break;
   			}
   		}
   		else
   		// Cos sie pochrzanilo
   		{
   			queryResultTable = new ResultTable();
   			break;
   		}
   	}
   }
   catch(Exception e)
   {
   	e.printStackTrace();
	ErrorLogger.log(e);
   }
   return;
}

//private Object sample;

private PredicateRegistry predicateRegistry;

private VariableRegistry variableRegistry;

private ArrayList<ResultTable> quantifierResultList = new ArrayList<ResultTable>();

private String quantifierString = "";

private ResultTable queryResultTable;
}

stat:
	^(STAT qtflist expr)
	{
		queryResultTable = $expr.resultTable;
		executeQuery();
	}
	;
	
qtflist:
	^(QTF qtf*)
	;

qtf:
	forall
	|
	exists
	;

forall:
	^(FORALL rng)
	{
		quantifierResultList.add($rng.resultTable);
		quantifierString = quantifierString + "A";
	}
	;

exists:
	^(EXISTS rng)
	{
		quantifierResultList.add($rng.resultTable);
		quantifierString = quantifierString + "E";
	}
	;

rng returns [ResultTable resultTable]
:
	varlist ^(EXPR expr)
	{
		$resultTable = $expr.resultTable;
	}
	;

varlist
:
	^(VAR ids+=ID+)
	{
		Iterator iter = $ids.iterator();
		while(iter.hasNext())
		{
			String id = ((CommonTree)iter.next()).getText();
			variableRegistry.add(new Variable(id));
		}
	}
	;

expr returns [ResultTable resultTable]
:
	or
	{
		$resultTable = $or.resultTable;
	}
	|
	and
	{
		$resultTable = $and.resultTable;
	}
	|
	quark
	{
		$resultTable = $quark.resultTable;
	}
	;
	
or returns [ResultTable resultTable]
:
	^(OR expr1=expr expr2=expr)
	{
		try
		{
			$resultTable = ResultTable.or($expr1.resultTable, $expr2.resultTable);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			ErrorLogger.log(e);
		}
	}
	;
	
and returns [ResultTable resultTable]
:
	^(AND expr1=expr expr2=expr)
	{
		try
		{
			$resultTable = ResultTable.and($expr1.resultTable, $expr2.resultTable);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			ErrorLogger.log(e);
		}
	}
	;

quark returns [ResultTable resultTable]
:
	predcall[true]
	{
		$resultTable = $predcall.resultTable;
	}
	|
	^(NOT predcall[false])
	{
		$resultTable = $predcall.resultTable;
	}
	;

predcall [boolean negval] returns [ResultTable resultTable]
:
	^(IS ID arg)
	{
		$resultTable = new ResultTable();
		try
		{
			if ($negval)
			{
				$resultTable= predicateRegistry.getResults($ID.text, $arg.resultTable);
			}
			else
			{
				$resultTable= predicateRegistry.getResults("NOT "+$ID.text, $arg.resultTable);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
			ErrorLogger.log(e);
		}
	}
	|
	^(REL ID arg1=arg arg2=arg)
	{
		$resultTable = new ResultTable();
		try
		{
			if ($negval)
			{
				$resultTable= predicateRegistry.getResults($ID.text, $arg1.resultTable, $arg2.resultTable);
			}
			else
			{
				$resultTable= predicateRegistry.getResults("NOT "+$ID.text, $arg1.resultTable, $arg2.resultTable);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
			ErrorLogger.log(e);
		}
	}
	;

arg returns [ResultTable resultTable]
:
	ID
	{
		try
		{
			$resultTable = predicateRegistry.getArgResultTable($ID.text);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			ErrorLogger.log(e);
		}
	}
	;
	
